package com.imgrate.migration.service;

import com.imgrate.migration.entity.BackupTask;
import com.imgrate.migration.entity.Server;
import com.imgrate.migration.repository.BackupTaskRepository;
import com.imgrate.migration.repository.ServerRepository;
import com.imgrate.migration.service.SshService.CommandResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class BackupService {
    
    private final BackupTaskRepository backupTaskRepository;
    private final ServerRepository serverRepository;
    private final SshService sshService;
    
    public List<BackupTask> getAllTasks() {
        return backupTaskRepository.findAllByOrderByCreatedAtDesc();
    }
    
    public Optional<BackupTask> getTaskById(Long id) {
        return backupTaskRepository.findById(id);
    }
    
    public BackupTask createBackupTask(BackupTask task) {
        task.setStatus("PENDING");
        task.setProgress(0);
        task.setCreatedAt(LocalDateTime.now());
        task.setUpdatedAt(LocalDateTime.now());
        
        // 计算下次运行时间
        calculateNextRunTime(task);
        
        BackupTask savedTask = backupTaskRepository.save(task);
        log.info("创建备份任务: {} (ID: {})", task.getTaskName(), savedTask.getId());
        return savedTask;
    }
    
    public BackupTask updateTaskStatus(Long id, String status, Integer progress, String errorMessage) {
        Optional<BackupTask> taskOpt = backupTaskRepository.findById(id);
        if (taskOpt.isPresent()) {
            BackupTask task = taskOpt.get();
            task.setStatus(status);
            if (progress != null) {
                task.setProgress(progress);
            }
            if (errorMessage != null) {
                task.setErrorMessage(errorMessage);
            }
            if ("RUNNING".equals(status) && task.getLastRunTime() == null) {
                task.setLastRunTime(LocalDateTime.now());
            }
            if (("COMPLETED".equals(status) || "FAILED".equals(status))) {
                task.setLastRunTime(LocalDateTime.now());
                // 计算下次运行时间
                calculateNextRunTime(task);
            }
            
            task.setUpdatedAt(LocalDateTime.now());
            BackupTask updatedTask = backupTaskRepository.save(task);
            log.info("更新备份任务状态: {} (ID: {}) - 状态: {}, 进度: {}%", 
                    task.getTaskName(), id, status, progress);
            return updatedTask;
        }
        throw new RuntimeException("备份任务不存在");
    }
    
    public void deleteTask(Long id) {
        backupTaskRepository.deleteById(id);
        log.info("删除备份任务ID: {}", id);
    }
    
    /**
     * 执行备份任务
     * @param taskId 任务ID
     */
    @Transactional
    public void executeBackup(Long taskId) {
        Optional<BackupTask> taskOpt = backupTaskRepository.findById(taskId);
        if (!taskOpt.isPresent()) {
            throw new RuntimeException("备份任务不存在");
        }
        
        BackupTask task = taskOpt.get();
        if (!"PENDING".equals(task.getStatus()) && !"COMPLETED".equals(task.getStatus())) {
            throw new RuntimeException("任务状态不正确，无法执行");
        }
        
        // 更新任务状态为运行中
        updateTaskStatus(taskId, "RUNNING", 0, null);
        
        try {
            // 获取源服务器信息
            Optional<Server> sourceServerOpt = serverRepository.findById(task.getSourceServerId());
            if (!sourceServerOpt.isPresent()) {
                throw new RuntimeException("源服务器不存在");
            }
            
            Server sourceServer = sourceServerOpt.get();
            
            // 执行具体的备份步骤
            performBackupSteps(task, sourceServer);
            
            // 更新任务状态为完成
            updateTaskStatus(taskId, "COMPLETED", 100, null);
            
        } catch (Exception e) {
            log.error("备份任务执行失败: {}", e.getMessage(), e);
            updateTaskStatus(taskId, "FAILED", task.getProgress(), e.getMessage());
            throw new RuntimeException("备份任务执行失败: " + e.getMessage());
        }
    }
    
    /**
     * 执行具体的备份步骤
     * @param task 备份任务
     * @param sourceServer 源服务器
     */
    private void performBackupSteps(BackupTask task, Server sourceServer) {
        try {
            // 步骤1: 连接到源服务器 (10%)
            updateTaskStatus(task.getId(), "RUNNING", 10, null);
            log.info("步骤1: 连接到源服务器 {}:{}", sourceServer.getHostname(), sourceServer.getPort());
            
            // 步骤2: 验证源服务器环境 (20%)
            updateTaskStatus(task.getId(), "RUNNING", 20, null);
            log.info("步骤2: 验证源服务器环境");
            validateServerEnvironment(sourceServer);
            
            // 步骤3: 准备备份数据 (30%)
            updateTaskStatus(task.getId(), "RUNNING", 30, null);
            log.info("步骤3: 准备备份数据");
            
            // 步骤4: 执行备份 (80%)
            updateTaskStatus(task.getId(), "RUNNING", 80, null);
            log.info("步骤4: 执行备份: {} -> {}", task.getSourcePath(), getTargetDescription(task));
            
            performBackup(task, sourceServer);
            
            // 步骤5: 验证备份结果 (90%)
            updateTaskStatus(task.getId(), "RUNNING", 90, null);
            log.info("步骤5: 验证备份结果");
            
            // 步骤6: 清理临时文件 (95%)
            updateTaskStatus(task.getId(), "RUNNING", 95, null);
            log.info("步骤6: 清理临时文件");
            
        } catch (Exception e) {
            log.error("备份步骤执行失败: {}", e.getMessage(), e);
            throw new RuntimeException("备份步骤执行失败: " + e.getMessage());
        }
    }
    
    /**
     * 验证服务器环境
     * @param server 服务器
     */
    private void validateServerEnvironment(Server server) {
        // 检查服务器连接
        SshService.ConnectionResult result = sshService.testConnection(server);
        if (!result.isSuccess()) {
            throw new RuntimeException("服务器连接失败: " + result.getMessage());
        }
        
        // 根据操作系统类型进行不同的环境验证
        if ("LINUX".equalsIgnoreCase(server.getOsType())) {
            validateLinuxEnvironment(server);
        } else if ("WINDOWS".equalsIgnoreCase(server.getOsType())) {
            validateWindowsEnvironment(server);
        }
    }
    
    /**
     * 验证Linux环境
     * @param server 服务器
     */
    private void validateLinuxEnvironment(Server server) {
        log.info("验证Linux环境: {}", server.getHostname());
        
        // 检查必要的命令是否存在
        String[] requiredCommands = {"rclone"};
        for (String command : requiredCommands) {
            try {
                String checkCommand = "which " + command;
                CommandResult result = sshService.executeCommand(server, checkCommand);
                if (!result.isSuccess()) {
                    log.warn("Linux服务器 {} 上未找到命令: {}", server.getHostname(), command);
                    throw new RuntimeException("Linux服务器 " + server.getHostname() + " 上未找到命令: " + command);
                } else {
                    log.info("Linux服务器 {} 上找到命令: {}", server.getHostname(), command);
                }
            } catch (Exception e) {
                log.warn("检查Linux服务器 {} 上的命令 {} 时出错: {}", server.getHostname(), command, e.getMessage());
                throw new RuntimeException("检查Linux服务器 " + server.getHostname() + " 上的命令 " + command + " 时出错: " + e.getMessage());
            }
        }
    }
    
    /**
     * 验证Windows环境
     * @param server 服务器
     */
    private void validateWindowsEnvironment(Server server) {
        log.info("验证Windows环境: {}", server.getHostname());
        
        // 检查必要的工具是否存在
        String[] requiredTools = {"rclone"};
        for (String tool : requiredTools) {
            try {
                String checkCommand = "where " + tool;
                CommandResult result = sshService.executeCommand(server, checkCommand);
                if (!result.isSuccess()) {
                    log.warn("Windows服务器 {} 上未找到工具: {}", server.getHostname(), tool);
                    throw new RuntimeException("Windows服务器 " + server.getHostname() + " 上未找到工具: " + tool);
                } else {
                    log.info("Windows服务器 {} 上找到工具: {}", server.getHostname(), tool);
                }
            } catch (Exception e) {
                log.warn("检查Windows服务器 {} 上的工具 {} 时出错: {}", server.getHostname(), tool, e.getMessage());
                throw new RuntimeException("检查Windows服务器 " + server.getHostname() + " 上的工具 " + tool + " 时出错: " + e.getMessage());
            }
        }
    }
    
    /**
     * 执行备份
     * @param task 备份任务
     * @param sourceServer 源服务器
     */
    private void performBackup(BackupTask task, Server sourceServer) {
        try {
            String backupCommand;
            
            if ("SERVER".equals(task.getTargetType())) {
                // 备份到服务器
                Optional<Server> targetServerOpt = serverRepository.findById(task.getTargetServerId());
                if (!targetServerOpt.isPresent()) {
                    throw new RuntimeException("目标服务器不存在");
                }
                
                Server targetServer = targetServerOpt.get();
                backupCommand = String.format(
                    "rclone copy %s %s@%s:%s --sftp-port=%d --sftp-pass=\"%s\"", 
                    task.getSourcePath(),
                    targetServer.getUsername(),
                    targetServer.getHostname(),
                    task.getTargetPath(),
                    targetServer.getPort(),
                    targetServer.getPassword()
                );
            } else {
                // 备份到对象存储
                String configName = "backup_" + task.getId();
                String configCommand = String.format(
                    "rclone config create %s %s access_key_id=%s secret_access_key=%s endpoint=%s",
                    configName,
                    task.getTargetType().toLowerCase(),
                    task.getTargetAccessKey(),
                    task.getTargetSecretKey(),
                    task.getTargetEndpoint()
                );
                
                // 先执行配置命令
                CommandResult configResult = sshService.executeCommand(sourceServer, configCommand);
                if (!configResult.isSuccess()) {
                    throw new RuntimeException("配置对象存储失败: " + configResult.getMessage());
                }
                
                backupCommand = String.format(
                    "rclone copy %s %s:%s/%s",
                    task.getSourcePath(),
                    configName,
                    task.getTargetBucket(),
                    task.getTaskName() + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"))
                );
            }
            
            CommandResult backupResult = sshService.executeCommand(sourceServer, backupCommand);
            if (!backupResult.isSuccess()) {
                throw new RuntimeException("备份失败: " + backupResult.getMessage());
            }
            
            log.info("备份完成: {}", backupCommand);
        } catch (Exception e) {
            log.error("备份执行失败: {}", e.getMessage(), e);
            throw new RuntimeException("备份执行失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取目标描述
     * @param task 备份任务
     * @return 目标描述
     */
    private String getTargetDescription(BackupTask task) {
        if ("SERVER".equals(task.getTargetType())) {
            return task.getTargetServerName() + ":" + task.getTargetPath();
        } else {
            return task.getTargetType() + ":" + task.getTargetBucket();
        }
    }
    
    /**
     * 计算下次运行时间
     * @param task 备份任务
     */
    private void calculateNextRunTime(BackupTask task) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime nextRunTime = null;
        
        switch (task.getScheduleType()) {
            case "ONCE":
                // 一次性任务，不设置下次运行时间
                nextRunTime = null;
                break;
            case "DAILY":
                // 每天运行
                nextRunTime = now.plusDays(1);
                break;
            case "WEEKLY":
                // 每周运行
                nextRunTime = now.plusWeeks(1);
                break;
            case "MONTHLY":
                // 每月运行
                nextRunTime = now.plusMonths(1);
                break;
            case "CRON":
                // CRON表达式，这里简化处理，设置为明天同一时间
                nextRunTime = now.plusDays(1);
                break;
            default:
                nextRunTime = null;
        }
        
        task.setNextRunTime(nextRunTime);
    }
    
    /**
     * 获取待执行的备份任务
     * @return 待执行的备份任务列表
     */
    public List<BackupTask> getPendingTasks() {
        return backupTaskRepository.findByStatusAndNextRunTimeLessThanEqual(
            "PENDING", LocalDateTime.now());
    }
}